package com.beta.cat.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.beta.cat.service.RedissonService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.*;

import java.time.Duration;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
public class RedissonServiceImpl implements RedissonService {

    protected RedissonClient redissonClient;

    @Override
    public RedissonClient getRedissonClient() {
        return redissonClient;
    }

    @Override
    public void setRedissonClient(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    @Override
    public boolean tryLock(String lockName, long waitTime) {
        try {
            RLock rLock = redissonClient.getLock(lockName);
            return rLock.tryLock(waitTime, TimeUnit.MILLISECONDS);
        } catch (Exception ex) {
            log.error("redisson try Lock失败：{}", ex.getMessage(), ex);
            return false;
        }
    }

    @Override
    public boolean tryLock(String lockName, long leaseTime, long waitTime) {
        try {
            RLock rLock = redissonClient.getLock(lockName);
            return rLock.tryLock(waitTime, leaseTime, TimeUnit.MILLISECONDS);
        } catch (Exception ex) {
            log.error("redisson try Lock失败：{}", ex.getMessage(), ex);
            return false;
        }
    }

    @Override
    public void unlock(String lockName) {
        try {
            RLock rLock = redissonClient.getLock(lockName);
            if (rLock.isLocked() && rLock.isHeldByCurrentThread()) {
                rLock.unlock();
            }
        } catch (Exception e) {
            log.error("redisson unLock失败：{}", e.getMessage(), e);
        }
    }

    @Override
    public boolean isLock(String lockName) {
        try {
            return redissonClient.getLock(lockName).isLocked();
        } catch (Exception e) {
            log.error("redisson isLock失败：{}", e.getMessage(), e);
            return false;//如果失败，则认为加锁失败！因为继续加锁也不会成功！
        }
    }

    @Override
    public boolean isHeldByCurrentThread(String lockName) {
        try {
            return redissonClient.getLock(lockName).isHeldByCurrentThread();
        } catch (Exception e) {
            log.error("redisson isHeldByCurrentThread失败：{}", e.getMessage(), e);
            return false;//如果失败，则认为加锁失败！因为继续加锁也不会成功！
        }
    }

    @Override
    public String getStr(String key) {
        try {
            RBucket<String> bucket = redissonClient.getBucket(key);
            return bucket.get();
        } catch (Exception e) {
            log.error("redisson getStr失败：{}", e.getMessage(), e);
            return null;
        }
    }

    @Override
    public void setStr(String key, String value) {
        try {
            RBucket bucket = redissonClient.getBucket(key);
            bucket.set(value);
        } catch (Exception e) {
            log.error("redisson setStr失败：{}", e.getMessage(), e);
        }
    }

    @Override
    @Deprecated
    public <T> T get(String key) {
        try {
            RBucket<T> bucket = redissonClient.getBucket(key);
            return bucket.get();
        } catch (Exception e) {
            log.error("redisson get失败：{}", e.getMessage(), e);
            return null;
        }
    }

    @Override
    public <T> T get(String key, Class<T> t) {
        try {
            RBucket<String> bucket = redissonClient.getBucket(key);
            return JSON.parseObject(bucket.get(), t);
        } catch (Exception e) {
            log.error("redisson get失败：{}", e.getMessage(), e);
            return null;
        }
    }

    @Override
    public <T> List<T> getList(String key, Class<T> t) {
        try {
            RBucket<String> bucket = redissonClient.getBucket(key);
            return JSON.parseArray(bucket.get(), t);
        } catch (Exception e) {
            log.error("redisson getList失败：{}", e.getMessage(), e);
            return null;
        }
    }

    @Override
    @Deprecated
    public void set(String key, Object value) {
        try {
            RBucket bucket = redissonClient.getBucket(key);
            bucket.set(JSON.toJSONString(value));
        } catch (Exception e) {
            log.error("redisson set失败：{}", e.getMessage(), e);
        }
    }

    @Override
    @Deprecated
    public void set(String key, Object value, long time) {
        try {
            RBucket bucket = redissonClient.getBucket(key);
            bucket.set(value, time, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            log.error("redisson set失败：{}", e.getMessage(), e);
        }
    }

    @Override
    public void setJson(String key, Object value) {
        try {
            RBucket bucket = redissonClient.getBucket(key);
            bucket.set(JSON.toJSONString(value));
        } catch (Exception e) {
            log.error("redisson setJSON失败：{}", e.getMessage(), e);
        }
    }

    @Override
    public void setJson(String key, Object value, long time) {
        try {
            RBucket bucket = redissonClient.getBucket(key);
            bucket.set(JSON.toJSONString(value), time, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            log.error("redisson setJSON失败：{}", e.getMessage(), e);
        }
    }

    @Override
    public void expire(String key, Duration expireTimeDuration) {
        try {
            RBucket bucket = redissonClient.getBucket(key);
            bucket.expire(expireTimeDuration.getSeconds(), TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("redisson expire失败：{}", e.getMessage(), e);
        }
    }

    @Override
    public long incr(String key) {
        try {
            RAtomicLong atomicLong = redissonClient.getAtomicLong(key);
            return atomicLong.incrementAndGet();
        } catch (Exception e) {
            log.error("redisson incr失败：{}", e.getMessage(), e);
            return -1;
        }
    }

    @Override
    public long incrBy(String key, long value) {
        try {
            RAtomicLong atomicLong = redissonClient.getAtomicLong(key);
            return atomicLong.addAndGet(value);
        } catch (Exception e) {
            log.error("redisson incrBy失败：{}", e.getMessage(), e);
            return -1;
        }
    }

    @Override
    public long decr(String key) {
        try {
            RAtomicLong atomicLong = redissonClient.getAtomicLong(key);
            return atomicLong.decrementAndGet();
        } catch (Exception e) {
            log.error("redisson decr失败：{}", e.getMessage(), e);
            return -1;
        }
    }

    @Override
    public boolean delete(String key) {
        try {
            RBucket bucket = redissonClient.getBucket(key);
            return bucket.delete();
        } catch (Exception e) {
            log.error("redisson delete失败：{}", e.getMessage(), e);
            return false;//删除不成功
        }
    }

    @Override
    public boolean bitSet(String key, long index, boolean value) {
        try {
            RBitSet set = redissonClient.getBitSet(key);
            return set.set(index, value);
        } catch (Exception e) {
            log.error("redisson bitSet失败：{}", e.getMessage(), e);
            return false;//判定为操作失败
        }
    }

    @Override
    public boolean bitGet(String key, long index) {
        try {
            RBitSet set = redissonClient.getBitSet(key);
            return set.get(index);
        } catch (Exception e) {
            log.error("redisson bitSet失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public Integer putSortedSet(String key, Double score, Object value, Duration expireTime) {
        try {
            RScoredSortedSet<Object> scoredSortedSet = redissonClient.getScoredSortedSet(key);

            Integer rank = scoredSortedSet.addAndGetRevRank(score, value);
            scoredSortedSet.expire(expireTime.getSeconds(), TimeUnit.SECONDS);

            return rank;
        } catch (Exception e) {
            log.error("redisson putSortedSet失败：{}", e.getMessage(), e);
            return -1;//返回null的话，业务代码中不太容易发现这个问题，在redis宕了之后，容易导致空指针异常，所以这里返回-1的方式。
        }
    }

    @Override
    public Integer putSortedSet(String key, Double score, Object value) {
        try {
            RScoredSortedSet<Object> scoredSortedSet = redissonClient.getScoredSortedSet(key);

            Integer rank = scoredSortedSet.addAndGetRevRank(score, value);
            return rank + 1;
        } catch (Exception e) {
            log.error("redisson putSortedSet失败：{}", e.getMessage(), e);
            return -1;//返回null的话，业务代码中不太容易发现这个问题，在redis宕了之后，容易导致空指针异常，所以这里返回-1的方式。
        }
    }

    /**
     * 獲取排行榜前top对象
     *
     * @param key
     * @param top
     * @return
     */
    @Override
    public List<Object> rankRange(String key, Integer top) {
        try {
            RScoredSortedSet<Object> scoredSortedSet = redissonClient.getScoredSortedSet(key);
            LinkedHashSet<Object> linkedHashSet = (LinkedHashSet) scoredSortedSet.valueRangeReversed(0D, false, scoredSortedSet.lastScore(), true, 0, top);
            return new ArrayList<>(linkedHashSet);
        } catch (Exception e) {
            log.error("redisson rankRange失败：{}", e.getMessage(), e);
            return null;
        }
    }


    @Override
    public RScoredSortedSet<Object> rankRangeAll(String key) {
        try {
            RScoredSortedSet<Object> scoredSortedSet = redissonClient.getScoredSortedSet(key);
            return scoredSortedSet;
        } catch (Exception e) {
            log.error("redisson rankRangeAll失败：{}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 获取排行榜数据,正向排列
     *
     * @param key      缓存key
     * @param minScore 起始值
     * @param maxCount 获取最大排行榜数据
     * @return
     */
    @Override
    public <T> List<T> rankRange(String key, Long minScore, Long maxScore, Integer maxCount, Class<T> t) {
        try {
            RScoredSortedSet<T> scoredSortedSet = redissonClient.getScoredSortedSet(key);
            ArrayList<T> value = (ArrayList) scoredSortedSet.valueRange(Double.valueOf(minScore), true, maxScore, false, 0, maxCount);
            return value;
        } catch (Exception e) {
            log.error("redisson rankRange失败：{}", e.getMessage(), e);
            return null;
        }
    }

    @Override
    public Integer getRank(String key, Object value) {
        try {
            RScoredSortedSet<Object> scoredSortedSet = redissonClient.getScoredSortedSet(key);
            return scoredSortedSet.revRank(value) + 1;
        } catch (Exception e) {
            log.error("redisson getRank失败：{}", e.getMessage(), e);
            return -1;
        }
    }

    @Override
    public Integer addScore(String key, Double addScore, Object value, Duration expireTime) {
        try {
            RScoredSortedSet<Object> scoredSortedSet = redissonClient.getScoredSortedSet(key);
            Integer rank = scoredSortedSet.addScoreAndGetRank(value, addScore);
            scoredSortedSet.expire(expireTime.getSeconds(), TimeUnit.SECONDS);
            return rank;
        } catch (Exception e) {
            log.error("redisson addScore失败：{}", e.getMessage(), e);
            return -1;
        }
    }

    @Override
    public void lPush(String key, String... values) {
        //redissonClient.getList()
        //
    }

    @Override
    public boolean zadd(String key, Long score, String value) {
        try {
            RScoredSortedSet rScoredSortedSet = redissonClient.getScoredSortedSet(key);
            return rScoredSortedSet.add(score, value);
        } catch (Exception e) {
            log.error("redisson zadd失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public Integer revrank(String key, String value) {
        try {
            RScoredSortedSet rScoredSortedSet = redissonClient.getScoredSortedSet(key);
            return rScoredSortedSet.revRank(value);
        } catch (Exception e) {
            log.error("redisson revrank失败：{}", e.getMessage(), e);
            return -1;
        }
    }

    @Override
    public Collection<String> zrevrange(String key, int start, int end) {
        try {
            RScoredSortedSet rScoredSortedSet = redissonClient.getScoredSortedSet(key);
            return rScoredSortedSet.valueRangeReversed(start, end);
        } catch (Exception e) {
            log.error("redisson zrevrange失败：{}", e.getMessage(), e);
            return null;
        }
    }

    @Override
    public boolean sadd(String key, Object value) {
        try {
            RSortedSet sortedSet = redissonClient.getSortedSet(key);
            return sortedSet.add(value);
        } catch (Exception e) {
            log.error("redisson sadd失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public boolean addList(String key, Object value) {
        try {
            RList rList = redissonClient.getList(key);
            return rList.add(value);
        } catch (Exception e) {
            log.error("redisson addList失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public <T> List<T> getRList(String key, Integer value, Class<T> t) {
        try {
            RList rList = redissonClient.getList(key);
            return rList.range(value);
        } catch (Exception e) {
            log.error("redisson getRList失败：{}", e.getMessage(), e);
            return null;
        }
    }

    @Override
    public Integer getSetLenth(String key) {
        try {
            RSortedSet sortedSet = redissonClient.getSortedSet(key);
            return sortedSet.size();
        } catch (Exception e) {
            log.error("redisson getSetLength失败：{}", e.getMessage(), e);
            return -1;
        }
    }

    @Override
    public RSortedSet getSet(String key) {
        try {
            RSortedSet sortedSet = redissonClient.getSortedSet(key);
            return sortedSet;
        } catch (Exception e) {
            log.error("redisson getSet失败：{}", e.getMessage(), e);
            return null;
        }
    }

    @Override
    public boolean setAdd(String key, Object value) {
        try {
            RSet<Object> set = this.redissonClient.getSet(key);
            return set.add(value);
        } catch (Exception e) {
            log.error("redisson setAdd失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public boolean setAddAll(String key, Set<Object> objectSet) {
        try {
            RSet<Object> set = this.redissonClient.getSet(key);
            return set.addAll(objectSet);
        } catch (Exception e) {
            log.error("redisson zrevrange失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public boolean saddAll(String key, Set<Object> set) {
        try {
            RSortedSet sortedSet = redissonClient.getSortedSet(key);
            return sortedSet.addAll(set);
        } catch (Exception e) {
            log.error("redisson saddAll失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public Integer getZSetSize(String key) {
        try {
            RSet<Object> set = redissonClient.getSet(key);
            return set.size();
        } catch (Exception e) {
            log.error("redisson getZSetSize失败：{}", e.getMessage(), e);
            return -1;
        }
    }

    @Override
    public boolean isSetExistsSync(String key, String param) {
        try {
            RSet<String> set = redissonClient.getSet(key);
            return set.contains(param);
        } catch (Exception e) {
            log.error("redisson isSetExistsSync失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public boolean isSetExists(String key, String param) {
        RSet<String> set = redissonClient.getSet(key);
        RFuture<Boolean> booleanRFuture = set.containsAsync(param);
        boolean result = false;
        try {
            result = booleanRFuture.get();
        } catch (InterruptedException e) {
            log.error("when exec containsAsync method InterruptedException! key:{}, param:{}, error:{}", key, param, e.getMessage());
        } catch (Exception e) {
            log.error("when exec containsAsync method Exception! key:{}, param:{}, error:{}", key, param, e.getMessage());
        }

        return result;
    }

    @Override
    public <T> T getMapValue(String key, Object mapKey, Class<T> t) {
        try {
            final RMap<String, String> map = redissonClient.getMap(key);
            final String v = map.get(mapKey);
            return JSONObject.parseObject(v, t);
        } catch (Exception e) {
            log.error("redisson getMapValue失败：{}", e.getMessage(), e);
            return null;
        }
    }

    @Override
    public <K, V> void setMap(String key, Map<K, V> mapParam) {
        try {
            final RMap<Object, Object> map = redissonClient.getMap(key);
            Map<Object, String> newMap = new HashMap<>(mapParam.size());
            mapParam.forEach((k, v) -> {
                newMap.put(k, JSONObject.toJSONString(v));
            });

            map.putAll(newMap);
        } catch (Exception e) {
            log.error("redisson setMap失败：{}", e.getMessage(), e);
        }
    }

    @Override
    public boolean isExistMap(String key) {
        try {
            final RMap<Object, Object> map = redissonClient.getMap(key);
            return map.isExists();
        } catch (Exception e) {
            log.error("redisson isExistMap失败：{}", e.getMessage(), e);
            return false;
        }
    }

    public boolean isExistMap(String key, Object mapKey) {
        try {
            final RMap<Object, Object> map = redissonClient.getMap(key);
            return map.containsKey(mapKey);
        } catch (Exception e) {
            log.error("redisson isExistMap失败：{}", e.getMessage(), e);
            return false;
        }
    }
}
